// |**| Opcon|OperationMango|**|Opcon|OperationMango|**|
// |**| Source Code for the FPS Operation Mango     |**|
// |**| Opcon|OperationMango|**|Opcon|OperationMango|**|

using System;

using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Audio;
using OpenTK.Audio.OpenAL;
using OpenTK.Input;
using Sirikata.BerkeliumSharp;
using System.Drawing;
using System.Drawing.Imaging;
using System.Collections;
using System.Collections.Generic;

namespace OperationMango
{
    class Game : GameWindow
    {
		

#region SetupDeveloperStuff

		#if DEBUG
			public const string ASSETS_DIRECTORY = ("../Assets/");
			public const string SHADERS_DIRECTORY = (ASSETS_DIRECTORY + "Shaders/");
			public const bool ISDEBUG = true;
		#else
			public const string ASSETS_DIRECTORY = ("../Assets/");
			public const string SHADERS_DIRECTORY = (ASSETS_DIRECTORY + "Shaders/");
			public const bool ISDEBUG = false;
		#endif
		
		public static System.IO.DirectoryInfo Assets_Directory = new System.IO.DirectoryInfo(ASSETS_DIRECTORY); 
		public static System.IO.DirectoryInfo Shaders_Directory = new System.IO.DirectoryInfo(SHADERS_DIRECTORY);
		
		
		
		
		
#endregion
		
		
		Polygon testpolygon;
		FileWatcher testfilewatcher;
		
		Matrix4 modelview;
		Matrix4 projection;
		Matrix4 temporary;
		
		ShaderBase testvertex;
        ShaderBase testfragment;
        ShaderProgram testprogram;
		
		uint TestTextureID;
		TextureTarget testTextureTarget;
		
		QuaternionCamera quatCamera;
		
		Grid DefaultGrid;
		
		KeyboardHotkey CurrentHotkey;
		
		Bitmap cursor;
		
		System.Windows.Forms.Cursor myCursor;
		
        /// <summary>Creates a 800x600 window with the specified title.</summary>
        public Game ()
            : base(800, 600, GraphicsMode.Default, "Operation Mango")
        {
            VSync = VSyncMode.On;
			Keyboard.KeyUp += KeyboardHotkeyHandler;
			FocusedChanged += FocusChangedHandler;
			
        }

        void FocusChangedHandler (object sender, EventArgs e)
        {
			if (quatCamera.MouseLookEnabled)
				quatCamera.MouseLookEnabled = Focused;
        }

        void KeyboardHotkeyHandler (object sender, KeyboardKeyEventArgs e)
        {
			
			Console.WriteLine("Key was : {0}", e.Key);
			if (e.Key == Key.Escape)
				Exit();
            if (e.Key == Key.C)
			{
				CurrentHotkey = KeyboardHotkey.Camera;
			}
			else if (e.Key == Key.V)
			{
				CurrentHotkey = KeyboardHotkey.None;
			}
			
			switch (CurrentHotkey) 
			{
			case KeyboardHotkey.Camera:
				switch(e.Key)
				{
				case(Key.Number1):
					quatCamera.SetCameraMode(CamMode.FirstPerson);
					break;
				case(Key.Number2):
					quatCamera.SetCameraMode(CamMode.FlightCamera);
					break;
				case Key.Number3:
					quatCamera.SetCameraMode(CamMode.NoClip);
					break;
				case Key.Tilde:
					quatCamera.MouseLookEnabled = Utilities.ToggleBoolean(quatCamera.MouseLookEnabled);
					break;
				default:
					break;
				}
				break;
			default:
				break;
			}
			
			switch (e.Key) 
			{
			case Key.F10:
				WindowState = Utilities.ToggleFullscreen(WindowState);
				quatCamera.FixMouse();
				break;
			default:
			break;
			}
        }

        protected override void OnLoad (EventArgs e)
        {
        	base.OnLoad (e);
        	GL.ClearColor (Color4.CornflowerBlue);
        	GL.Enable (EnableCap.DepthTest);
   
			TestCode ();
			
			if (ISDEBUG) 
			{
				this.WindowState = WindowState.Normal;		
			}
			else 
			{
				this.WindowState =  WindowState.Fullscreen;
			}
			
			
        }
        
        protected void TestCode ()
        {
        	ShadersTest ();
        	TranslateTest ();
        	FilesTest ();
			
			cursor = new Bitmap(Assets_Directory.FullName + "/Textures/Cursor.png");
			
			myCursor = new System.Windows.Forms.Cursor(cursor.GetHicon());
			
			System.Windows.Forms.Cursor.Current = myCursor;
			
			testfilewatcher = new FileWatcher(Shaders_Directory.FullName);
			
			try 
			{
				ImageGDI.LoadFromDisk(Assets_Directory.FullName + "Textures/Grid.png", out TestTextureID, out testTextureTarget);
			} 
			catch (ArgumentException ex) 
			{
				Console.WriteLine ("Exception = {0}", ex.Message);
			}
			Console.WriteLine ("TestTextureID={0}", TestTextureID);
			
			DefaultGrid = new Grid(500, 500);
			
			GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest);
			
			quatCamera = new QuaternionCamera(new Vector3(0, 5, 0), Quaternion.FromAxisAngle(Vector3.UnitZ, 50) , Mouse, Keyboard, true, this);
			quatCamera.SetCameraMode(CamMode.FlightCamera);
			quatCamera.UpdateParentGame(this);
			quatCamera.MouseXSensitivity = 0.3f;
			quatCamera.MouseYSensitivity = 0.3f;
			quatCamera.ZFar = 64000.0f;
		}

        
        protected void FilesTest ()
        {

        	string glsl;
        	ASCIIFileHelper.WriteString (Shaders_Directory.FullName + "tester.txt", "THis is a Testythingymabobby");
        	ASCIIFileHelper.ReadStringToEnd (Shaders_Directory.FullName + "tester.txt", out glsl);
        	Console.WriteLine ("glsl={0}", glsl);
		}
        
        protected void TranslateTest ()
		{
			testpolygon = new Polygon (8);
			testpolygon.SetVertex(Color.Aqua, new Vector3(0.0f, 0.0f, 4.0f), 0);
			testpolygon.SetVertex(Color.Purple, new Vector3(1.0f, 0.0f, 4.0f), 1);
			testpolygon.SetVertex(Color.DarkSlateGray, new Vector3(0.0f, 1.0f, 4.0f), 2);
			testpolygon.SetVertex(Color.DarkGreen, new Vector3(1.0f, 1.0f, 4.0f), 3);
			testpolygon.SetVertex(Color.Goldenrod, new Vector3(0.0f, 1.0f, 5.0f), 4);
			testpolygon.SetVertex(Color.LawnGreen, new Vector3(1.0f, 1.0f, 5.0f), 5);
			testpolygon.SetVertex(Color.LightPink, new Vector3(0.0f, 0.0f, 5.0f), 6);
			testpolygon.SetVertex(Color.Gainsboro, new Vector3(1.0f, 0.0f, 5.0f), 7);

		}
        
        protected void ShadersTest ()
		{
			testvertex = new ShaderBase (Shaders_Directory.FullName + "Simple_VS.glsl", ShaderType.VertexShader, true);
        	testfragment = new ShaderBase (Shaders_Directory.FullName + "Simple_FS.glsl", ShaderType.FragmentShader, true);
        	testprogram = new ShaderProgram ();
        	testfragment.CompileShader ();
        	testvertex.CompileShader ();
        	testprogram.AttachShader (testfragment);
        	testprogram.AttachShader (testvertex);
        	testprogram.LinkProgram ();
        	testprogram.ActivateProgram();
   
		}

        /// <summary>
        /// Called when your window is resized. Set your viewport here. It is also
        /// a good place to set up your projection matrix (which probably changes
        /// along when the aspect ratio of your window).
        /// </summary>
        /// <param name="e">Not used.</param>
        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);

            GL.Viewport(ClientRectangle.X, ClientRectangle.Y, ClientRectangle.Width, ClientRectangle.Height);
			
			quatCamera.AspectRatio = (float)Math.Round((double)(ClientRectangle.Width / ClientRectangle.Height), 4);
			
			quatCamera.GetModelviewMatrix(out modelview);
			quatCamera.GetProjectionMatrix(out projection);
			
			GL.MatrixMode(MatrixMode.Modelview);
			GL.LoadMatrix(ref modelview);
			
			GL.MatrixMode(MatrixMode.Projection);
            GL.LoadMatrix(ref projection);
        }
		
		
        /// <summary>
        /// Called when it is time to setup the next frame. Add you game logic here.
        /// </summary>
        /// <param name="e">Contains timing information for framerate independent logic.</param>
        protected override void OnUpdateFrame (FrameEventArgs e)
        {
        	base.OnUpdateFrame (e);
			quatCamera.Update(e.Time);
			quatCamera.GetModelviewMatrix(out modelview);			
			GL.MatrixMode(MatrixMode.Modelview);
			GL.LoadMatrix(ref modelview);

        }



        /// <summary>
        /// Called when it is time to render the next frame. Add your rendering code here.
        /// </summary>
        /// <param name="e">Contains timing information.</param>
        protected override void OnRenderFrame (FrameEventArgs e)
        {
			
        	base.OnRenderFrame (e);
        	GL.Clear (ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

			GL.MatrixMode (MatrixMode.Modelview);
			DefaultGrid.Render(e.Time);
			GL.Disable(EnableCap.Texture2D);
            GL.Begin (BeginMode.TriangleStrip);


			
            GL.Color3 (testpolygon.GetColor (0));
        	GL.Vertex3 (testpolygon.GetPosition (0));
        	GL.Color3 (testpolygon.GetColor (1));
        	GL.Vertex3 (testpolygon.GetPosition (1));
        	GL.Color3 (testpolygon.GetColor (2));
        	GL.Vertex3 (testpolygon.GetPosition (2));
        	GL.Color3 (testpolygon.GetColor (3));
        	GL.Vertex3 (testpolygon.GetPosition (3));
			GL.Color3(testpolygon.GetColor(4));
			GL.Vertex3(testpolygon.GetPosition(4));
			GL.Color3(testpolygon.GetColor(5));
			GL.Vertex3(testpolygon.GetPosition(5));
			GL.Color3(testpolygon.GetColor(6));
			GL.Vertex3(testpolygon.GetPosition(6));
			GL.Color3(testpolygon.GetColor(7));
			GL.Vertex3(testpolygon.GetPosition(7));
			GL.Color3(testpolygon.GetColor(5));
			GL.Vertex3(testpolygon.GetPosition(5));
			
			GL.End();
			GL.PushClientAttrib(ClientAttribMask.ClientVertexArrayBit);
			GL.ClientActiveTexture(TextureUnit.Texture0);
			GL.BindTexture(testTextureTarget, TestTextureID);
			GL.Enable(EnableCap.Texture2D);
			GL.Begin(BeginMode.Quads);

			GL.Color3(Color.White);
			GL.TexCoord2(1.0, 1.0);   
			GL.Vertex3(0.0, -3.0, 1.0);
			GL.TexCoord2(1.0, 0.0);   
			GL.Vertex3(0.0, -3.0, 6.0);
			GL.TexCoord2(0.0, 0.0);   
			GL.Vertex3(5.0, -3.0, 6.0);
			GL.TexCoord2(0.0, 1.0);   
			GL.Vertex3(5.0, -3.0, 1.0);
			
            GL.End();
			
			GL.PopClientAttrib();
            SwapBuffers();
			this.Title = "Operation Mango | FPS: " + System.Math.Round(this.RenderFrequency);
        }

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            // The 'using' idiom guarantees proper resource cleanup.
            // We request 30 UpdateFrame events per second, and unlimited
            // RenderFrame events (as fast as the computer can handle).
            using (Game game = new Game())
            {
				
				game.Title = "Operation Mango FPS: " + game.RenderFrequency;
                game.Run(30.0);
            }
        }
		

    }
}